package com.example.musicaiap.data.repository

import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import com.example.musicaiap.domain.model.Song
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.coroutineContext

/**
 * 本地音乐扫描器
 * 负责从设备媒体库扫描音乐文件并转换为应用的Song模型
 * 使用MediaStore API来查询设备上的音频文件
 */
@Singleton
class LocalMusicScanner @Inject constructor(
    @ApplicationContext private val context: Context
) {
    // 用于日志记录的TAG，便于在Logcat中过滤日志
    private val TAG = "LocalMusicScanner"
    
    /**
     * 扫描设备上的音乐文件
     * 该方法会查询设备媒体库中标记为音乐的音频文件，并转换为应用的Song模型
     *
     * 实现细节：
     * 1. 使用IO调度器在后台线程执行，避免阻塞主线程
     * 2. 设置超时时间，避免扫描时间过长
     * 3. 尝试多个存储卷，增加扫描范围
     * 4. 使用MediaStore查询系统媒体库
     * 5. 添加日志记录便于调试
     *
     * @return 扫描到的音乐文件列表
     */
    suspend fun scanLocalMusic(): List<Song> = withContext(Dispatchers.IO) {
        val songs = mutableListOf<Song>()
        
        try {
            // 添加日志记录
            Log.d(TAG, "开始扫描本地音乐（仅限MP3格式）")
            
            // 为整个操作设置超时，避免长时间运行，但增加时间
            withTimeout(120000L) { // 120秒超时，给予更多时间扫描
                // 查询所有可能的音乐存储卷
                val volumes = listOf(
                    MediaStore.VOLUME_EXTERNAL, // 主存储
                    MediaStore.VOLUME_EXTERNAL_PRIMARY, // 同主存储，但更明确
                    "external_primary", // 外部存储
                    "external" // 通用外部存储
                )
                
                // 防止重复的音乐文件
                val processedIds = mutableSetOf<String>()
                
                // 遍历每个存储卷进行扫描
                for (volume in volumes) {
                    Log.d(TAG, "扫描存储卷: $volume")
                    
                    // 获取存储卷的URI
                    val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        try {
                            // Android 10+使用带卷名的URI
                            MediaStore.Audio.Media.getContentUri(volume)
                        } catch (e: Exception) {
                            Log.e(TAG, "无法获取存储卷URI: $volume, ${e.message}")
                            continue // 跳过这个卷
                        }
                    } else {
                        // Android 9及以下使用通用外部存储URI
                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                    }
                    
                    // 查询字段：定义需要获取的音频文件属性
                    val projection = arrayOf(
                        MediaStore.Audio.Media._ID,          // 音频文件ID
                        MediaStore.Audio.Media.TITLE,        // 标题
                        MediaStore.Audio.Media.ARTIST,       // 艺术家
                        MediaStore.Audio.Media.ALBUM,        // 专辑名
                        MediaStore.Audio.Media.DURATION,     // 时长
                        MediaStore.Audio.Media.DATA,         // 文件路径
                        MediaStore.Audio.Media.ALBUM_ID,     // 专辑ID，用于获取封面
                        MediaStore.Audio.Media.SIZE,         // 文件大小
                        MediaStore.Audio.Media.MIME_TYPE     // 文件类型
                    )
                    
                    // 仅限制查询MP3格式（MIME类型为audio/mpeg）
                    val selection = "${MediaStore.Audio.Media.MIME_TYPE} = 'audio/mpeg'"
                    
                    // 按标题排序
                    val sortOrder = "${MediaStore.Audio.Media.TITLE} ASC"
                    
                    // 查询媒体库
                    try {
                        Log.d(TAG, "【$volume】开始查询MediaStore，仅限MP3格式")
                        context.contentResolver.query(
                            collection,
                            projection,
                            selection,
                            null,
                            sortOrder
                        )?.use { cursor ->
                            // 获取各个列的索引
                            val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)
                            val titleColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)
                            val artistColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)
                            val albumColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)
                            val durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)
                            val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
                            val albumIdColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID)
                            val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)
                            val mimeTypeColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.MIME_TYPE)
                            
                            // 添加日志记录
                            Log.d(TAG, "【$volume】找到 ${cursor.count} 首音乐")
                            
                            var count = 0
                            while (cursor.moveToNext()) {
                                // 定期检查协程是否被取消，提高响应性
                                coroutineContext.ensureActive()
                                
                                // 从cursor获取音频文件的各个属性
                                val id = cursor.getLong(idColumn)
                                val title = cursor.getString(titleColumn) ?: "未知标题"
                                val artist = cursor.getString(artistColumn) ?: "未知艺术家"
                                val album = cursor.getString(albumColumn) ?: "未知专辑"
                                val duration = cursor.getLong(durationColumn)
                                val path = cursor.getString(dataColumn)
                                val albumId = cursor.getLong(albumIdColumn)
                                val size = cursor.getLong(sizeColumn)
                                val mimeType = cursor.getString(mimeTypeColumn)
                                
                                // 记录文件信息用于调试
                                Log.d(TAG, "文件: $title, 路径: $path, 大小: $size, 类型: $mimeType, 时长: $duration")
                                
                                // 创建音乐文件的URI，用于播放
                                val contentUri = ContentUris.withAppendedId(
                                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                                    id
                                )
                                
                                // 专辑封面的URI，用于显示封面
                                val albumArtUri = ContentUris.withAppendedId(
                                    Uri.parse("content://media/external/audio/albumart"),
                                    albumId
                                ).toString()
                                
                                // 创建唯一ID
                                val uniqueId = UUID.nameUUIDFromBytes(
                                    "${path}_${System.currentTimeMillis()}_${id}_${title}_${artist}_${album}_${size}".toByteArray()
                                ).toString()
                                
                                // 带前缀的唯一ID
                                val songId = "media_${uniqueId}"
                                
                                Log.d(TAG, "MediaStore生成唯一ID: $songId, 标题: $title, 路径: $path")
                                
                                // 创建Song对象
                                val song = Song(
                                    id = songId,                  // 唯一ID
                                    title = title,                 // 标题
                                    artist = artist,               // 艺术家
                                    album = album,                 // 专辑名
                                    duration = duration,           // 时长(毫秒)
                                    coverUrl = albumArtUri,        // 封面图片URL
                                    url = contentUri.toString(),   // 音频文件URL - 使用content://URI格式
                                    lyricUrl = null,               // 歌词URL(本地音乐通常没有)
                                    isVip = false                  // 是否是VIP歌曲
                                )
                                
                                // 记录URI信息
                                Log.d(TAG, "创建Song: $title, ID: $songId, URI: ${contentUri.toString()}")
                                
                                // 只添加非重复的歌曲
                                if (!processedIds.contains(song.id)) {
                                    songs.add(song)
                                    processedIds.add(song.id)
                                    
                                    // 每处理10首歌曲记录一次日志，用于监控扫描进度
                                    count++
                                    if (count % 10 == 0) {
                                        Log.d(TAG, "【$volume】已处理 $count 首音乐")
                                    }
                                }
                            }
                            
                            Log.d(TAG, "【$volume】扫描完成，发现 ${cursor.count} 首音乐")
                        }
                    } catch (e: Exception) {
                        Log.e(TAG, "扫描存储卷出错: $volume, ${e.message}")
                    }
                }
                
                // 如果使用MediaStore扫描没有找到任何音乐，或者是旧版Android，尝试直接扫描文件系统
                if (songs.isEmpty() || Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                    try {
                        // 尝试直接扫描文件系统
                        val filesystemSongs = scanExternalDirectories()
                        
                        // 添加非重复的歌曲
                        for (song in filesystemSongs) {
                            if (!processedIds.contains(song.id)) {
                                songs.add(song)
                                processedIds.add(song.id)
                            }
                        }
                    } catch (e: Exception) {
                        Log.e(TAG, "扫描外部目录失败: ${e.message}")
                    }
                }
                
                Log.d(TAG, "所有扫描完成，共找到 ${songs.size} 首音乐")
            }
        } catch (e: Exception) {
            // 记录异常
            Log.e(TAG, "扫描本地音乐失败: ${e.message}", e)
            // 重新抛出异常，以便上层处理
            throw e
        }
        
        return@withContext songs
    }

    /**
     * 扫描外部目录中的音乐文件（用于旧版Android或直接文件系统访问）
     * 用于当MediaStore查询无法获取SD卡文件时的备选方案
     * 
     * @return 扫描到的歌曲列表
     */
    private suspend fun scanExternalDirectories(): List<Song> {
        val songs = mutableListOf<Song>()
        
        try {
            // 记录当前只扫描MP3文件
            Log.d(TAG, "开始扫描外部目录，仅限MP3格式文件")
            
            // 常见的音乐目录路径
            val musicPaths = listOf(
                "/sdcard/Music",               // 标准音乐目录
                "/storage/emulated/0/Music",   // 内部存储音乐目录
                "/storage/sdcard0/Music",      // 旧版内部存储音乐目录
                "/storage/sdcard1/Music",      // 外置SD卡音乐目录
                "/storage/extSdCard/Music",    // 三星设备SD卡音乐目录
                "/mnt/sdcard/Music",           // 另一可能的SD卡路径
                "/sdcard",                     // SD卡根目录 
                "/storage/emulated/0",         // 内部存储根目录
                "/storage/sdcard1",            // 外置SD卡根目录
                "/storage/extSdCard"           // 三星设备SD卡根目录
            )
            
            // 获取设备所有存储目录的根路径
            val externalStorageDirs = context.getExternalFilesDirs(null)
            for (dir in externalStorageDirs) {
                if (dir != null) {
                    // 去掉应用专有部分，获取根目录
                    val path = dir.absolutePath.substringBefore("/Android")
                    if (path.isNotEmpty()) {
                        Log.d(TAG, "发现外部存储目录: $path")
                        // 检查此目录中的音乐文件
                        val musicDir = "$path/Music"
                        scanDirectoryForMusicFiles(musicDir, songs)
                        // 也扫描根目录
                        scanDirectoryForMusicFiles(path, songs)
                    }
                }
            }
            
            // 扫描预定义路径
            for (path in musicPaths) {
                Log.d(TAG, "尝试扫描外部目录: $path")
                scanDirectoryForMusicFiles(path, songs)
            }
            
            Log.d(TAG, "外部目录扫描完成，共找到 ${songs.size} 首音乐")
        } catch (e: Exception) {
            Log.e(TAG, "扫描外部目录异常: ${e.message}")
        }
        
        return songs
    }

    /**
     * 扫描指定目录中的音乐文件
     * 
     * @param directoryPath 要扫描的目录路径
     * @param songs 用于存储找到的歌曲的列表
     */
    private suspend fun scanDirectoryForMusicFiles(directoryPath: String, songs: MutableList<Song>) {
        try {
            val directory = java.io.File(directoryPath)
            
            // 检查目录是否存在且可读
            if (!directory.exists() || !directory.canRead()) {
                Log.d(TAG, "目录不存在或无法读取: $directoryPath")
                return
            }
            
            // 递归扫描此目录及其子目录中的所有文件
            directory.listFiles()?.forEach { file ->
                // 检查协程是否被取消
                coroutineContext.ensureActive()
                
                if (file.isDirectory) {
                    // 递归扫描子目录，但不扫描某些系统目录
                    val lowerPath = file.name.lowercase()
                    if (!lowerPath.startsWith(".") && 
                        !lowerPath.contains("android") && 
                        !lowerPath.equals("dcim", true) &&
                        !lowerPath.equals("pictures", true)) {
                        scanDirectoryForMusicFiles(file.absolutePath, songs)
                    }
                } else if (isAudioFile(file)) {
                    // 找到音频文件，创建Song对象
                    val song = createSongFromFile(file)
                    if (song != null) {
                        songs.add(song)
                        Log.d(TAG, "在文件系统中找到音乐文件: ${song.title}, 路径: ${file.absolutePath}")
                    }
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "扫描目录失败: $directoryPath, ${e.message}")
        }
    }

    /**
     * 检查文件是否是音频文件
     * 
     * @param file 要检查的文件
     * @return 如果是MP3音频文件返回true，否则返回false
     */
    private fun isAudioFile(file: java.io.File): Boolean {
        val name = file.name.lowercase()
        // 仅检查MP3格式文件
        return name.endsWith(".mp3")
    }

    /**
     * 从文件创建Song对象
     * 
     * @param file 音频文件
     * @return 创建的Song对象，如果无法创建则返回null
     */
    private fun createSongFromFile(file: java.io.File): Song? {
        return try {
            // 从文件名提取标题，去掉扩展名
            val title = file.nameWithoutExtension
            
            // 使用file://方案的URI
            val fileUri = "file://${file.absolutePath}"
            
            // 创建默认封面URL，使用Android资源作为默认图标
            // 使用特殊标记表示需要使用默认图标
            val defaultCoverUrl = "default://music_icon"
            
            // 创建更具有唯一性的ID
            // 使用文件的绝对路径、大小和最后修改时间的组合
            val uniqueId = UUID.nameUUIDFromBytes(
                "${file.absolutePath}_${file.length()}_${file.lastModified()}".toByteArray()
            ).toString()
            
            // 创建带有fileUri前缀的唯一ID，保持URI标识的同时确保唯一性
            val songId = "file_${uniqueId}_${file.nameWithoutExtension}"
            
            Log.d(TAG, "生成唯一ID: $songId, 文件路径: ${file.absolutePath}")
            
            // 创建Song对象
            val song = Song(
                id = songId,                   // 使用唯一ID
                title = title,                 // 标题
                artist = "未知艺术家",            // 直接文件扫描无法获取艺术家信息
                album = "未知专辑",              // 直接文件扫描无法获取专辑信息
                duration = 0,                  // 直接文件扫描无法获取时长
                coverUrl = defaultCoverUrl,    // 使用默认封面标记
                url = fileUri,                 // 文件URI保持不变，用于播放
                lyricUrl = null,               // 无歌词
                isVip = false                  // 非VIP
            )
            
            // 记录URI信息
            Log.d(TAG, "创建文件Song: $title, ID: $songId, URI: $fileUri")
            
            return song
        } catch (e: Exception) {
            Log.e(TAG, "创建Song对象失败: ${file.absolutePath}, ${e.message}")
            null
        }
    }
} 